{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# Using agents\n",
        "\n",
        "This is an agent specifically optimized for doing retrieval when necessary and also holding a conversation.\n",
        "\n",
        "To start, we will set up the retriever we want to use, and then turn it into a retriever tool. Next, we will use the high level constructor for this type of agent. Finally, we will walk through how to construct a conversational retrieval agent from components."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Setup\n",
        "### Dependencies\n",
        "\n",
        "We’ll use an OpenAI chat model and embeddings and a Memory vector store in this walkthrough, but everything shown here works with any [ChatModel](/docs/modules/model_io/chat) or [LLM](/docs/modules/model_io/llms), [Embeddings](/docs/modules/data_connection/text_embedding/), and [VectorStore](/docs/modules/data_connection/vectorstores/) or [Retriever](/docs/modules/data_connection/retrievers/).\n",
        "\n",
        "We’ll use the following packages:\n",
        "\n",
        "```bash\n",
        "npm install --save langchain @langchain/openai\n",
        "```\n",
        "\n",
        "We need to set our environment variable for OpenAI:\n",
        "\n",
        "```bash\n",
        "export OPENAI_API_KEY=YOUR_KEY\n",
        "```"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### LangSmith\n",
        "\n",
        "Many of the applications you build with LangChain will contain multiple steps with multiple invocations of LLM calls. As these applications get more and more complex, it becomes crucial to be able to inspect what exactly is going on inside your chain or agent. The best way to do this is with [LangSmith](https://smith.langchain.com/).\n",
        "\n",
        "Note that LangSmith is not needed, but it is helpful. If you do want to use LangSmith, after you sign up at the link above, make sure to set your environment variables to start logging traces:\n",
        "\n",
        "\n",
        "```bash\n",
        "export LANGCHAIN_TRACING_V2=true\n",
        "export LANGCHAIN_API_KEY=YOUR_KEY\n",
        "```"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## The Retriever\n",
        "\n",
        "To start, we need a retriever to use! The code here is mostly just example code. Feel free to use your own retriever and skip to the section on creating a retriever tool."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "metadata": {},
      "outputs": [],
      "source": [
        "import { TextLoader } from \"langchain/document_loaders/fs/text\";\n",
        "\n",
        "const loader = new TextLoader(\"../../../../../examples/state_of_the_union.txt\");\n",
        "const documents = await loader.load();"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "texts.length 41\n"
          ]
        }
      ],
      "source": [
        "import { CharacterTextSplitter } from \"langchain/text_splitter\";\n",
        "import { MemoryVectorStore } from \"langchain/vectorstores/memory\";\n",
        "import { OpenAIEmbeddings } from \"@langchain/openai\";\n",
        "\n",
        "const textSplitter = new CharacterTextSplitter({ chunkSize: 1000, chunkOverlap: 0 });\n",
        "const texts = await textSplitter.splitDocuments(documents);\n",
        "console.log(\"texts.length\", texts.length);\n",
        "const embeddings = new OpenAIEmbeddings();\n",
        "const db = await MemoryVectorStore.fromDocuments(texts, embeddings);"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "metadata": {},
      "outputs": [],
      "source": [
        "const retriever = db.asRetriever();"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Retriever Tool\n",
        "\n",
        "Now we need to create a tool for our retriever. The main things we need to pass in are a name for the retriever as well as a description. These will both be used by the language model, so they should be informative."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 18,
      "metadata": {},
      "outputs": [],
      "source": [
        "import { createRetrieverTool } from \"langchain/tools/retriever\";\n",
        "\n",
        "const tool = createRetrieverTool(retriever, {\n",
        "  name: \"search_state_of_union\",\n",
        "  description:\n",
        "    \"Searches and returns excerpts from the 2022 State of the Union.\",\n",
        "});\n",
        "const tools = [tool];"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Agent Constructor\n",
        "\n",
        "Here, we will use the high level `createOpenaiToolsAgent` API to construct the agent.\n",
        "\n",
        "Notice that beside the list of tools, the only thing we need to pass in is a language model to use.\n",
        "Under the hood, this agent is using the OpenAI tool-calling capabilities, so we need to use a ChatOpenAI model."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 19,
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "[\n",
              "  SystemMessagePromptTemplate {\n",
              "    lc_serializable: \u001b[33mtrue\u001b[39m,\n",
              "    lc_kwargs: {\n",
              "      prompt: PromptTemplate {\n",
              "        lc_serializable: \u001b[33mtrue\u001b[39m,\n",
              "        lc_kwargs: {\n",
              "          template: \u001b[32m\"You are a helpful assistant\"\u001b[39m,\n",
              "          inputVariables: [],\n",
              "          templateFormat: \u001b[32m\"f-string\"\u001b[39m,\n",
              "          partialVariables: {}\n",
              "        },\n",
              "        lc_runnable: \u001b[33mtrue\u001b[39m,\n",
              "        name: \u001b[90mundefined\u001b[39m,\n",
              "        lc_namespace: [ \u001b[32m\"langchain_core\"\u001b[39m, \u001b[32m\"prompts\"\u001b[39m, \u001b[32m\"prompt\"\u001b[39m ],\n",
              "        inputVariables: [],\n",
              "        outputParser: \u001b[90mundefined\u001b[39m,\n",
              "        partialVariables: {},\n",
              "        template: \u001b[32m\"You are a helpful assistant\"\u001b[39m,\n",
              "        templateFormat: \u001b[32m\"f-string\"\u001b[39m,\n",
              "        validateTemplate: \u001b[33mtrue\u001b[39m\n",
              "      }\n",
              "    },\n",
              "    lc_runnable: \u001b[33mtrue\u001b[39m,\n",
              "    name: \u001b[90mundefined\u001b[39m,\n",
              "    lc_namespace: [ \u001b[32m\"langchain_core\"\u001b[39m, \u001b[32m\"prompts\"\u001b[39m, \u001b[32m\"chat\"\u001b[39m ],\n",
              "    prompt: PromptTemplate {\n",
              "      lc_serializable: \u001b[33mtrue\u001b[39m,\n",
              "      lc_kwargs: {\n",
              "        template: \u001b[32m\"You are a helpful assistant\"\u001b[39m,\n",
              "        inputVariables: [],\n",
              "        templateFormat: \u001b[32m\"f-string\"\u001b[39m,\n",
              "        partialVariables: {}\n",
              "      },\n",
              "      lc_runnable: \u001b[33mtrue\u001b[39m,\n",
              "      name: \u001b[90mundefined\u001b[39m,\n",
              "      lc_namespace: [ \u001b[32m\"langchain_core\"\u001b[39m, \u001b[32m\"prompts\"\u001b[39m, \u001b[32m\"prompt\"\u001b[39m ],\n",
              "      inputVariables: [],\n",
              "      outputParser: \u001b[90mundefined\u001b[39m,\n",
              "      partialVariables: {},\n",
              "      template: \u001b[32m\"You are a helpful assistant\"\u001b[39m,\n",
              "      templateFormat: \u001b[32m\"f-string\"\u001b[39m,\n",
              "      validateTemplate: \u001b[33mtrue\u001b[39m\n",
              "    }\n",
              "  },\n",
              "  MessagesPlaceholder {\n",
              "    lc_serializable: \u001b[33mtrue\u001b[39m,\n",
              "    lc_kwargs: { optional: \u001b[33mtrue\u001b[39m, variableName: \u001b[32m\"chat_history\"\u001b[39m },\n",
              "    lc_runnable: \u001b[33mtrue\u001b[39m,\n",
              "    name: \u001b[90mundefined\u001b[39m,\n",
              "    lc_namespace: [ \u001b[32m\"langchain_core\"\u001b[39m, \u001b[32m\"prompts\"\u001b[39m, \u001b[32m\"chat\"\u001b[39m ],\n",
              "    variableName: \u001b[32m\"chat_history\"\u001b[39m,\n",
              "    optional: \u001b[33mtrue\u001b[39m\n",
              "  },\n",
              "  HumanMessagePromptTemplate {\n",
              "    lc_serializable: \u001b[33mtrue\u001b[39m,\n",
              "    lc_kwargs: {\n",
              "      prompt: PromptTemplate {\n",
              "        lc_serializable: \u001b[33mtrue\u001b[39m,\n",
              "        lc_kwargs: {\n",
              "          template: \u001b[32m\"{input}\"\u001b[39m,\n",
              "          inputVariables: \u001b[36m[Array]\u001b[39m,\n",
              "          templateFormat: \u001b[32m\"f-string\"\u001b[39m,\n",
              "          partialVariables: {}\n",
              "        },\n",
              "        lc_runnable: \u001b[33mtrue\u001b[39m,\n",
              "        name: \u001b[90mundefined\u001b[39m,\n",
              "        lc_namespace: [ \u001b[32m\"langchain_core\"\u001b[39m, \u001b[32m\"prompts\"\u001b[39m, \u001b[32m\"prompt\"\u001b[39m ],\n",
              "        inputVariables: [ \u001b[32m\"input\"\u001b[39m ],\n",
              "        outputParser: \u001b[90mundefined\u001b[39m,\n",
              "        partialVariables: {},\n",
              "        template: \u001b[32m\"{input}\"\u001b[39m,\n",
              "        templateFormat: \u001b[32m\"f-string\"\u001b[39m,\n",
              "        validateTemplate: \u001b[33mtrue\u001b[39m\n",
              "      }\n",
              "    },\n",
              "    lc_runnable: \u001b[33mtrue\u001b[39m,\n",
              "    name: \u001b[90mundefined\u001b[39m,\n",
              "    lc_namespace: [ \u001b[32m\"langchain_core\"\u001b[39m, \u001b[32m\"prompts\"\u001b[39m, \u001b[32m\"chat\"\u001b[39m ],\n",
              "    prompt: PromptTemplate {\n",
              "      lc_serializable: \u001b[33mtrue\u001b[39m,\n",
              "      lc_kwargs: {\n",
              "        template: \u001b[32m\"{input}\"\u001b[39m,\n",
              "        inputVariables: [ \u001b[32m\"input\"\u001b[39m ],\n",
              "        templateFormat: \u001b[32m\"f-string\"\u001b[39m,\n",
              "        partialVariables: {}\n",
              "      },\n",
              "      lc_runnable: \u001b[33mtrue\u001b[39m,\n",
              "      name: \u001b[90mundefined\u001b[39m,\n",
              "      lc_namespace: [ \u001b[32m\"langchain_core\"\u001b[39m, \u001b[32m\"prompts\"\u001b[39m, \u001b[32m\"prompt\"\u001b[39m ],\n",
              "      inputVariables: [ \u001b[32m\"input\"\u001b[39m ],\n",
              "      outputParser: \u001b[90mundefined\u001b[39m,\n",
              "      partialVariables: {},\n",
              "      template: \u001b[32m\"{input}\"\u001b[39m,\n",
              "      templateFormat: \u001b[32m\"f-string\"\u001b[39m,\n",
              "      validateTemplate: \u001b[33mtrue\u001b[39m\n",
              "    }\n",
              "  },\n",
              "  MessagesPlaceholder {\n",
              "    lc_serializable: \u001b[33mtrue\u001b[39m,\n",
              "    lc_kwargs: { optional: \u001b[33mfalse\u001b[39m, variableName: \u001b[32m\"agent_scratchpad\"\u001b[39m },\n",
              "    lc_runnable: \u001b[33mtrue\u001b[39m,\n",
              "    name: \u001b[90mundefined\u001b[39m,\n",
              "    lc_namespace: [ \u001b[32m\"langchain_core\"\u001b[39m, \u001b[32m\"prompts\"\u001b[39m, \u001b[32m\"chat\"\u001b[39m ],\n",
              "    variableName: \u001b[32m\"agent_scratchpad\"\u001b[39m,\n",
              "    optional: \u001b[33mfalse\u001b[39m\n",
              "  }\n",
              "]"
            ]
          },
          "execution_count": 19,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "import { pull } from \"langchain/hub\";\n",
        "import { ChatPromptTemplate } from \"@langchain/core/prompts\";\n",
        "\n",
        "const prompt = await pull<ChatPromptTemplate>(\"hwchase17/openai-tools-agent\");\n",
        "prompt.promptMessages"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 20,
      "metadata": {},
      "outputs": [],
      "source": [
        "import { ChatOpenAI } from \"@langchain/openai\";\n",
        "\n",
        "const llm = new ChatOpenAI({ temperature: 0 });"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 21,
      "metadata": {},
      "outputs": [],
      "source": [
        "import { createOpenAIToolsAgent, AgentExecutor } from \"langchain/agents\";\n",
        "\n",
        "const agent = await createOpenAIToolsAgent({\n",
        "  llm,\n",
        "  tools,\n",
        "  prompt\n",
        "});\n",
        "const agentExecutor = new AgentExecutor({\n",
        "  agent,\n",
        "  tools,\n",
        "});"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "We can now try it out!"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "metadata": {},
      "outputs": [],
      "source": [
        "const result1 = await agentExecutor.invoke({ input: \"hi im bob\" });"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "\u001b[32m\"Hello Bob! How can I assist you today?\"\u001b[39m"
            ]
          },
          "execution_count": 9,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "result1.output"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Notice that it now does retrieval"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 26,
      "metadata": {},
      "outputs": [],
      "source": [
        "const result2 = await agentExecutor.invoke({ \n",
        "  input: `what did the president say about ketanji brown jackson in the most recent state of the union? The current date is ${new Date().toDateString()}`\n",
        "});"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 27,
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "\u001b[32m\"In the most recent State of the Union, the President mentioned Ketanji Brown Jackson as his nominee \"\u001b[39m... 176 more characters"
            ]
          },
          "execution_count": 27,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "result2.output;"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "See a LangSmith trace for the run above [here](https://smith.langchain.com/public/02281666-7124-402e-bd12-722fb58976e5/r)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Notice that the follow up question asks about information previously retrieved, so no need to do another retrieval"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 30,
      "metadata": {},
      "outputs": [],
      "source": [
        "const result3 = await agentExecutor.invoke({\n",
        "  input: \"how long ago did the president nominate ketanji brown jackson? Use all the tools to find the answer.\"\n",
        "})"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 31,
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "\u001b[32m\"The president nominated Ketanji Brown Jackson 4 days ago.\"\u001b[39m"
            ]
          },
          "execution_count": 31,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "result3.output;"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "See a LangSmith trace for the run above [here](https://smith.langchain.com/public/2b9ade9d-1f7e-4ae6-bb28-567f96a669f0/r)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "For more on how to use agents with retrievers and other tools, head to the [Agents](/docs/modules/agents) section."
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Deno",
      "language": "typescript",
      "name": "deno"
    },
    "language_info": {
      "file_extension": ".ts",
      "mimetype": "text/x.typescript",
      "name": "typescript",
      "nb_converter": "script",
      "pygments_lexer": "typescript",
      "version": "5.3.3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 2
}
